package org.ligson.springboot.redis.config;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author zhangrl
 */
@Configuration
@Slf4j
public class ContextRedisConfig {

    @Bean
    @ConditionalOnProperty(name = "crux.context.redis.enable", havingValue = "true", matchIfMissing = false)
    @ConfigurationProperties(prefix = "crux.context.redis")
    public ContextRedisProperties contextRedisProperties1() {
        return new ContextRedisProperties();
    }

    @Bean
    @ConditionalOnProperty(name = "drux.context.redis.enable", havingValue = "true", matchIfMissing = false)
    @ConfigurationProperties(prefix = "drux.context.redis")
    public ContextRedisProperties contextRedisProperties2() {
        return new ContextRedisProperties();
    }

    @Bean
    public RedisConnectionFactory contextLettuceConnectionFactory(RedisConnectionFactory redisConnectionFactory,
                                                                  @Autowired(required = false)
                                                                  @Qualifier("contextRedisProperties1") ContextRedisProperties properties) {
        if (properties == null) {
            log.info("【ContextRedis】使用的是默认Redis连接工厂:{}", redisConnectionFactory);
            return redisConnectionFactory;
        }
        LettuceConnectionFactory lettuceConnectionFactory;
        if (properties.isEnable()) {
            ContextRedisConnectionConfiguration contextRedisConnectionConfiguration = new ContextRedisConnectionConfiguration(properties);
            if (contextRedisConnectionConfiguration.getProperties().getCluster() == null) {
                lettuceConnectionFactory = new LettuceConnectionFactory(contextRedisConnectionConfiguration.getStandaloneConfig());
            } else {
                if (contextRedisConnectionConfiguration.getClusterConfiguration() != null) {
                    lettuceConnectionFactory = new LettuceConnectionFactory(contextRedisConnectionConfiguration.getClusterConfiguration());
                } else {
                    log.info("【ContextRedis】使用的是默认Redis连接工厂:{}", redisConnectionFactory);
                    return redisConnectionFactory;
                }
            }
        } else {
            log.info("【ContextRedis】使用的是默认Redis连接工厂:{}", redisConnectionFactory);
            return redisConnectionFactory;
        }
        log.info("【ContextRedis】使用的是自定义Redis连接工厂:{}", lettuceConnectionFactory);
        return lettuceConnectionFactory;

    }

    @Bean("contextRedisTemplate")
    public RedisTemplate<String, Object> contextRedisTemplate(@Qualifier("contextLettuceConnectionFactory") RedisConnectionFactory contextLettuceConnectionFactory, ObjectMapper objectMapper) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        ObjectMapper mapper = new ObjectMapper();
        mapper.setFilterProvider(new FilterProvider() {
            @SuppressWarnings("deprecation")
            @Override
            public com.fasterxml.jackson.databind.ser.BeanPropertyFilter findFilter(Object filterId) {
                return null;
            }

            @Override
            public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {
                return null;
            }
        });
        mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(mapper);
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(jsonSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(jsonSerializer);
        redisTemplate.setConnectionFactory(contextLettuceConnectionFactory);
        return redisTemplate;
    }
}
